/**
 * 数字框插件
 * author : 陆楚良
 * email  : lu_chuliang@sina.com
 * version: 1.0.0
 * date   : 2015/10/20
 *
 * https://git.oschina.net/luchg/jquery.numIpt.js
 *
 * License: http://www.apache.org/licenses/LICENSE-2.0
 *
 * $(".j-num").numIpt({
 *     $input: '.j-ipt',
 *     $del  : '.j-del',
 *     $add  : '.j-add',
 *     max   : 1000,
 *     min   : 0,
 *     onChange: function(value){
 *         // 防止出现小数的值
 *         this.value(parseInt(value));
 *     }
 * });
 */
!function(){
    function numIpt($){
        if(!$.fn.numIpt){
            // 解决js加减法精度问题
            var addition = function(a, b){
                var ra=0,rb=0,m;
                try{ra=a.toString().split(".")[1].length}catch(e){}
                try{rb=b.toString().split(".")[1].length}catch(e){}
                m=Math.pow(10,Math.max(ra,rb));
                return (a*m+b*m)/m;
            };
            var undefined = void 0;
            /**
             * numIpt([op])
             * @param  {Object} op 配置选项
             *                     $input    可选，输入框选择器，缺省'input'
             *                     $add      可选，“+”按钮选择器，缺省'.j-add'
             *                     $del      可选，“-”按钮选择器，缺省'.j-del'
             *                     min       可选，最小值，缺省null(不限制)
             *                     max       可选，最大值，缺省null(不限制)
             *                     unit      可选，单位，用于设置add或del时对应的增加、减少量，缺省值1
             *                     onChange  可选，Function类型，当输入框的值发生变化时触发，方法内的上下文this对象则是当前控件的对象，缺省null
             *                     extend    可选，用于更深一层的功能扩展，方法内的上下文this对象则是当前控件的对象，缺省null
             * @return {jQuery}
             */
            $.fn.numIpt = function(op){
                this.each(function(){
                    var _ = $.extend({
                        $input  : 'input',
                        $add    : '.j-add',
                        $del    : '.j-del',
                        min     : null,
                        max     : null,
                        unit    : 1,
                        onChange: null,
                        extend  : null
                    }, op);
                    var o = {_:_};
                    _.$input = $(_.$input, this);
                    _.$add   = $(_.$add  , this);
                    _.$del   = $(_.$del  , this);
                    _.value  = Number(_.$input.val());
                    if(!isFinite(_.value)){
                        _.value = _.min!==null ? _.min : 0;
                    }
                    _.$input.val(_.value);
                    /**
                     * value([value])
                     * @param  {Number} value 可选，在需要的情况下，传递参数可更改表单value的值
                     * @return {Number}       返回当前value
                     */
                    o.value  = function(value){
                        if(value!==undefined){
                            value = Number(value);
                            if(value!==_.value && isFinite(value)){
                                if($.type(_.min)=="number" && value<_.min){value=_.min}
                                if($.type(_.max)=="number" && value>_.max){value=_.max}
                                _.value = value;
                                _.$input.val(value);
                                $.type(_.onChange)=="function" && _.onChange.call(o, value);
                            }
                        }
                        return _.value;
                    };
                    /**
                     * 追加
                     * @param  {Number} unit 可选，自定义元单位的值，例：当传递0.1时，追加0.1，否则追加原配置里的unit的值
                     */
                    o.add = function(unit){
                        unit = unit || _.unit;
                        o.value(addition(_.value, unit));
                    };
                    /**
                     * 减少
                     * @param  {Number} unit 可选，自定义元单位的值，例：当传递0.1时，减少0.1，否则减少原配置里的unit的值
                     */
                    o.del = function(unit){
                        unit = unit || _.unit;
                        o.value(addition(_.value, -unit));
                    };
                    /**
                     * 修改或获取min值
                     * @param  {Number} value 可选，有参数为修改，反之获取
                     * @return {Number}
                     */
                    o.min = function(value){
                        if(value!==undefined){
                            _.min = Number(value);
                            _.value<_.min && o.value(_.min);
                        }
                        return _.min;
                    };
                    /**
                     * 修改或获取max值
                     * @param  {Number} value 可选，有参数为修改，反之获取
                     * @return {Number}
                     */
                    o.max = function(value){
                        if(value!==undefined){
                            _.max = Number(value);
                            _.value>_.max && o.value(_.max);
                        }
                        return _.max;
                    };
                    /**
                     * 修改或获取unit值
                     * @param  {Number} value 可选，有参数为修改，反之获取
                     * @return {Number}
                     */
                    o.unit = function(value){
                        if(value!==undefined){
                            _.unit = Number(value);
                        }
                        return _.unit;
                    };
                    var timer;
                    var add = function(){o.add()};
                    var del = function(){o.del()};
                    var cls = function(){clearTimeout(timer);clearInterval(timer)};
                    var Set = function(f){
                        timer = setTimeout(function(){
                            timer = setInterval(f, 100);
                        }, 300);
                    };
                    _.$add.on("click", function(){add();cls();})
                          .on("mousedown",function(){cls();Set(add);})
                          .on("mouseout", function(){cls()});
                    _.$del.on("click", function(){del();cls();})
                          .on("mousedown", function(){cls();Set(del);})
                          .on("mouseout", function(){cls()});
                    _.$input.on("change", function(){o.value(this.value)});
                    $.type(_.extend)=="function" && _.extend.call(o);
                });
                return this;
            };
        }
        return $;
    };
    // RequireJS && SeaJS
    if(typeof define==="function"){
        define(function(){return numIpt});
    // NodeJS
    }else if(typeof exports!=="undefined"){
        module.exports = numIpt;
    }else{
        numIpt(this.jQuery);
    }
}();
